/**
 * 包名：com.pactera.config
 * 文件名：BrowerSecurityConfig.java
 * 版本信息：1.0.0
 * 日期：2019年1月7日-下午6:06:21
 * Copyright (c) 2019 Pactera 版权所有
 */
 
package com.pactera.config.security;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

//Security配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) //启用security方法注解
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
	
	 @Autowired
	 private SelfUserDetailsService selfUserDetailsService; //自定义实现用户认证业务类
	
//	 @Autowired
//	 private ApiAuthenticationEntryPoint authEntryPoint; //未认证控制类		

     @Autowired
     private ApiAuthenticationSuccessHandler authSuccessHandler; //认证成功后控制类

     @Autowired
     private ApiAuthenticationFailureHandler authFailureHandler; //认证失败后控制类
    
     @Autowired
     private ApiAccessDeniedHandler accessDeniedHandler;//未授权控制类

//    @Autowired
//    private ApiLogoutSuccessHandler logoutSuccessHandler;//注销成功后控制类
    
     @Autowired
     private DataSource dataSource; //默认数据源
    
     private int rememberMeSeconds = 3600; //记住密码有效时间

	 @Override
	 public void configure(WebSecurity web) throws Exception {
		//允许匿名访问的资源路径配置
	    web.ignoring().antMatchers(
	    		"/login",
	    		"/logout",
	    		"/login/**",
	    		"/js/**",
	    		"/css/**",
	    		"/font/**",
	    		"/plugins/**",
	    		"/favicon.ico",
	    		"/img/**",
	    		"/frame/**",
	    		"/swagger-ui.html", 
	    		"/swagger-resources/**",
	    		"/v2/api-docs",
	    		"/webjars/**"
	    );
	 }
    
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
		//认证授权配置
		.authorizeRequests()
		
		//允许匿名访问资源路径(web.ignoring().antMatchers配置)
 		.antMatchers()
 		.permitAll()
 		
 		//其他所有资源都需登录认证后访问
		.anyRequest().authenticated() 		 
		.antMatchers("/admin").hasAuthority("ADMIN") //认证后拥有“ADMIN”权限才可以访问/admin，否则进入未授权控制
		
		//允许iframe嵌套
		.and().headers().frameOptions().disable()
		
		//关闭csrf防护
		.and().csrf().disable()
        .exceptionHandling()
//      .authenticationEntryPoint(authEntryPoint) 	//自定义未认证访问控制
        .accessDeniedHandler(accessDeniedHandler)   //自定义登录状态未授权访问控制
        
         //登录配置
        .and()
		.formLogin()								//启用formLogin
		.usernameParameter("account") 				//用户名参数key自定义(默认为username)
		.passwordParameter("pwd")     				//密码参数key自定义(默认为password)
		.loginPage("/login")	      				//登录页访问地址
		.loginProcessingUrl("/signin")  			//登录认证请求地址(无需实现,提交请求这个地址即可)
//		.defaultSuccessUrl("/home")     			//认证 成功后跳转页访问地址 (未设置successHandler情况下生效)
//		.failureForwardUrl("/failure")              //认证失败后跳转页访问地址 (未设置failureHandler情况下生效)
		.successHandler(authSuccessHandler) 		//认证成功控制
        .failureHandler(authFailureHandler) 		//认证失败控制
		.permitAll()
		
         //登出配置
		.and()
		.logout()									//启用退出
		.logoutUrl("/signout") 						//退出接口(无需实现,直接请求这个地址即可登出)
		.logoutSuccessUrl("/login") 				//退出后跳转页面访问地址(未设置logoutSuccessUrl时生效)
//		.logoutSuccessHandler(logoutSuccessHandler) //退出成功后响应控制(可实现Json响应) 
		.permitAll()								
		.deleteCookies("JSESSIONID")				//登出后删除cookie
		.invalidateHttpSession(true)				//登出后销毁session
		
		 //记住我配置    
		.and()
        .rememberMe()								 //启用"记住我"
//      .rememberMeParameter("rememberMe")			 //记住我参数key自定义
        .tokenRepository(persistentTokenRepository())//记住我登录成功后往数据库保存token数据接口实现
        .tokenValiditySeconds(rememberMeSeconds)	 //有效时间(单位:秒)
        .userDetailsService(selfUserDetailsService)  //记住我登录成功后，调用userDetailsService查询用户信息
		;

        //session管理
        http.sessionManagement().invalidSessionUrl("/login");			 //session失效后跳转
        http.sessionManagement().maximumSessions(1).expiredUrl("/login");//只允许一个用户登录,如果同一个账户两次登录,那么第一个账户将被踢下线,跳转到登录页面
//      .maxSessionsPreventsLogin(true)
	}
	
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 加入自定义的安全认证
//         auth.authenticationProvider(provider);
		
		 //加入自定义用户信息service并设置加密策略
         auth.userDetailsService(selfUserDetailsService).passwordEncoder(passwordEncoder());
	}
	
	@Bean
	public PasswordEncoder passwordEncoder() {
//	     return new BCryptPasswordEncoder();
	     return new SelfMd5PasswordEncoder();
	}
    
    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        //启动时自动生成相应表，可以在JdbcTokenRepositoryImpl里自己执行CREATE_TABLE_SQL脚本生成表
        //自动创建数据库表，使用一次后注释掉，不然会报错
//        jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }
}
